      
#include <jni.h>
#include <matrix.h>

extern vm_matrix vm_jdouble_to_matrix(JNIEnv *, jdoubleArray, jint);
extern void      vm_matrix_to_jdouble(JNIEnv *, jdoubleArray, vm_matrix *);
extern void      vm_free_jdouble_matrix(JNIEnv *, jdoubleArray, vm_matrix *);


jdoubleArray Java_net_matvec_Matrix_vm_1read_1matrix(JNIEnv *env, 
    jclass cls, jstring file, jobject dest){

  char *file_name = (char *)(*env)->GetStringUTFChars(env, file, 0);
  vm_matrix *m = vm_read_matrix(file_name);
  (*env)->ReleaseStringUTFChars(env, file, file_name);
  if (m == NULL) {
    vm_free_matrix(m);
    return NULL;
  }
  
  /* If the returned array isnt null then... */
  
  /* Make the jdoubleArray */
  jdoubleArray m_data = (*env)->NewDoubleArray(env, m->rows * m->columns);
  if (m_data == NULL) return NULL;
  vm_matrix_to_jdouble(env, m_data, m);

  /* Now set the rows/columns in the Matrix object we were passed. */
  jfieldID row_id = (*env)-> GetFieldID(env, cls, "rows", "I");
  jfieldID col_id = (*env)-> GetFieldID(env, cls, "columns", "I");

  (*env)->SetIntField(env, dest, row_id, m->rows);
  (*env)->SetIntField(env, dest, col_id, m->columns);
  vm_free_matrix(m);
  return m_data;

}

void Java_net_matvec_Matrix_vm_1multiply(JNIEnv *env,
    jobject obj, jdoubleArray m1, jint m1d, 
    jdoubleArray m2, jint m2d, jdoubleArray res){

  vm_matrix mat1 = vm_jdouble_to_matrix(env, m1, m1d);
  //vm_print_matrix(&mat1, "  ");
  vm_matrix mat2 = vm_jdouble_to_matrix(env, m2, m2d);
  //vm_print_matrix(&mat2, "  ");
  vm_matrix *mat_r = vm_matrix_mult(&mat1, &mat2);
  if (mat_r == NULL) { // Error occured
    vm_free_jdouble_matrix(env, m1, &mat1);
    vm_free_jdouble_matrix(env, m2, &mat2);
    // Implement: throw an exception.
    fprintf(stderr, "[Java_net_matvec_Matrix_vm_1multiply]\n");
    fprintf(stderr, "    Error caught during matrix multiply.\n");
  } else {
    //vm_print_matrix(mat_r, " >");
    vm_matrix_to_jdouble(env, res, mat_r);
    vm_free_matrix(mat_r);
    vm_free_jdouble_matrix(env, m1, &mat1);
    vm_free_jdouble_matrix(env, m2, &mat2);
  }
}

void Java_net_matvec_Matrix_vm_1transpose(JNIEnv *env, 
    jobject obj, jdoubleArray m, jdoubleArray res){



}

jdouble Java_net_matvec_Matrix_vm_1determinant(JNIEnv *env, 
    jobject obj, jdoubleArray m){



  return 0;

}

void Java_net_matvec_Matrix_vm_1inverse(JNIEnv *env, 
     jobject obj, jdoubleArray m, jdoubleArray res){



}

void Java_net_matvec_Matrix_vm_1minor_1matrix(JNIEnv *env, 
    jobject obj, jdoubleArray m, jint r, jint c, jdoubleArray res){



}

jdouble Java_net_matvec_Matrix_vm_1cofactor(JNIEnv *env, 
    jobject obj, jdoubleArray m, jint r, jint c){


  
  return 0;

}

void Java_net_matvec_Matrix_vm_1adjoint(JNIEnv *env, 
    jobject obj, jdoubleArray m, jdoubleArray res){



}

void Java_net_matvec_Matrix_vm_1print_1matrix(JNIEnv *env, 
    jobject obj, jdoubleArray m, jint r, jstring pre){

  vm_matrix mtx = vm_jdouble_to_matrix(env, m, r);
  char *prepend = (char *)(*env)->GetStringUTFChars(env, pre, NULL);
  vm_print_matrix(&mtx, prepend);
  (*env)->ReleaseStringUTFChars(env, pre, prepend);
  vm_free_jdouble_matrix(env, m, &mtx);

}
